#ifndef __C_PROC_SEMAPHORE_H__
#define __C_PROC_SEMAPHORE_H__

#include "std/debug.h"
#include "arch/atomic.h"
#include "kernel/wait.h"

#ifdef __cplusplus
extern "C" {
#endif

typedef struct semaphore
{
	atomic_t count;
	int sleepers;
	wait_queue_head_t wait;
}
semaphore_t;

#define SEMAPHORE_INITIALIZER(name, cnt) \
	{ ATOMIC_INIT(cnt), 0, WAIT_QUEUE_HEAD_INITIALIZER((name).wait) }

#define DECLARE_SEMAPHORE(name, cnt)	\
	semaphore_t name = SEMAPHORE_INITIALIZER(name, cnt)

#define DECLARE_MUTEX(name)	DECLARE_SEMAPHORE(name, 1)

void up(semaphore_t* sem);
void down(semaphore_t* sem);

static inline void sem_init(semaphore_t* sem, uint cnt)
{
	kassert(NULL != sem);
	atomic_set(&sem->count, cnt);
	sem->sleepers = 0;
	init_wait_queue(&sem->wait);
}

#define mutex_init(sem)	sem_init(sem, 1)

static inline void sem_enter(semaphore_t* sem)
{
	kassert(NULL != sem);
	if (atomic_add_negative(-1, &sem->count))
		down(sem);
}

static inline void sem_exit(semaphore_t* sem)
{
	kassert(NULL != sem);
	if (atomic_add_zero_or_negative(1, &sem->count))
		up(sem);
}

#ifdef __cplusplus
}
#endif
#endif
/* EOF */
